瓦片预缓存 Sample详情
最后更新时间:2020年12月11日
功能介绍
在线地图服务是移动终端常用的出图方式,在线地图服务通常是以瓦片为出图单元,最终将瓦片按照一定的规则拼接出图。为了给用户提供流畅、高效、快速的地图浏览体验,MapGIS Mobile不仅采用了高性能的地图渲染引擎,还提供了自动缓存的策略。在加载在线瓦片地图时,系统会自动将浏览过的范围、级别的地图进行自动缓存,存储到移动设备中,再次显示该区域的地图时直接读取离线本地数据,不用请求在线服务,从而使得地图能够非常迅速地渲染展示。这是MapGIS Mobile提供的自动缓存策略,存在一定的局限性,对于没有浏览过的区域的地图不会进行缓存,这无法满足要求在断网情况下同样能够浏览任意级别、任意区域地图的场景。于是,瓦片预缓存功能应运而生。
为了提高在线瓦片地图的加载速度,地图瓦片可以在终端预生成本地缓存,客户端浏览地图时可直接读取,这种技术被称作为瓦片预缓存技术。对于移动端来说,受限于硬件水平、网络速度、存储空间等因素,实现与PC终端相同的地图浏览及交互体验却相当困难,瓦片预缓存技术便在一定程度上解决了上述问题;另一方面,瓦片预缓存在在线浏览地图时动态缓存到本地存储,当在离线的时候亦可以浏览相同地图,这在野外作业中尤为重要。
瓦片预缓存实现的原理:在网络通畅情况下,根据用户需求,按照范围、级别将在线地图瓦片在终端生成本地缓存瓦片,存储到本地数据库中。从而在网络未连接的情况下,客户端直接读取本地缓存瓦片,同样能够进行地图的展示浏览。
MapGIS Mobile支持多种来源的在线地图,其中能够使用瓦片预缓存功能的数据类型包括:MapGIS IGServer在线瓦片地图、WMS地图服务、WMTS地图服务、天地图、Google地图、百度地图、高德地图、OSM地图、Bing地图等。
在缓存时,可以设置地图的级别范围、地图范围来实现更精确、更有针对性的瓦片缓存。
功能接口
瓦片预缓存功能对应API为com.zondy.mapgis.map的ImageLayer类接口(10.3版本:com.zondy.mapgis.core.map.ServerLayer),核心接口如下所示:
接口 | 说明 |
---|---|
ImageLayer.setTileCacheDir()【10.3:ServerLayer.setCacheLocation()】 | 设置缓存目录 |
ImageLayer.setTilePreFetchListener | 设置预缓存状态监听 |
ImageLayer.prefetch() | 预缓存指定范围、指定缩放级内的图像 |
无此接口【10.3:ServerLayer.stopFetch()】 | 停止预缓存 |
ImageLayer.deleteTileCache()【10.3:ServerLayer.clearCache()】 | 清除缓存 |
ImageLayer.setAccessMode() | 设置地图服务访问模式(CacheOnly/ServerAndCache/ServerOnly) |
实现方法
瓦片预缓存的大体实现方法如下所示:
(1)加载地图:首先需要加载能够进行瓦片预缓存功能的在线地图,并获取待进行缓存的ImageLayer图层对象;
(2)准备预缓存条件:选择需要缓存的地图范围、瓦片级别范围;
(3)设置监听:利用setTilePreFetchListener接口监听瓦片缓存的进度、状态;
(4)开始缓存:调用preFetch方法开始缓存;
(5)显示缓存:在缓存完成之后,可调用缓存进行显示。
实现过程
1
加载在线瓦片地图,以IGServer瓦片地图服务为例。
//缓存路径 private String strCacheDir = FilePath.PHONE_SDCARD_PATH + "/MapGISSample/TileCache/"; //服务图层1:igserver中的瓦片服务 serverLayer1 = new ImageLayer(); MapServer mapServer1 = ImageLayer.createMapServer(MapServer.MAPSERVER_TYPE_IGSERVER_TILE); //设置地图服务地址 mapServer1.setURL("http://develop.smaryun.com:6163/igs/rest/mrms/tile/WorldJWTile"); //为mapserver设置名称,须在setMapServer之前执行,创建的缓存文件会使用到此名称 mapServer1.setName("IGServer瓦片服务"); //设置缓存路径,必须在调用setMapServer之前执行,因为调用setMapServer的时候就会自动创建缓存了 serverLayer1.setTileCacheDir(strCacheDir); //为服务图层设置地图服务 serverLayer1.setMapServer(mapServer1); //地图对象 map1 = new Map(); map1.append(serverLayer1); //加载地图 mapView.setMapAsync(map1, new MapViewFinishCallback() { @Override public void onDidFinish(boolean arg0) { if (arg0) { //地图加载成功 } } });
代码说明:(1)进行瓦片预缓存的ImageLayer服务图层,需定义为成员变量。(2)设置缓存路径setTileCacheDir()必须要在调用setMapServer()之前执行,因为调用setMapServer()的时候就会自动创建缓存了。
2
在进行瓦片缓存时,需要设置缓存的地图范围,由于瓦片地图采用了分级显示的机制,所以进行缓存时,也需要选择缓存的瓦片级别。在缓存时将会只缓存此地图范围内设置的级别的地图。设置的地图范围越小,缓存消耗时间越少,缓存后的文件数据量越小。选择的瓦片级别范围越多,消耗时间越多。级别越大的瓦片,缓存时消耗的时间越多。根据实际需求选择合理的地图范围、瓦片级别范围。
//获取地图服务对象 final MapServer mapServer = serverlayer.getMapServer(); //连接数据,在缓存igserver中的瓦片服务的时候需要使用 new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub //igserver中的瓦片服务需要先连接数据,才能获取其信息 long a = mapServer.connectData(); if (a > 0) { Message m = new Message(); m.what = 1; mhandler.sendMessage(m); } else { Message m = new Message(); m.what = 0; mhandler.sendMessage(m); // Toast.makeText(TilePreFetch_Activity.this, "连接数据失败,请确保网络已连接", Toast.LENGTH_SHORT).show(); } } }).start(); mhandler = new Handler() { public void handleMessage(Message msg) { super.handleMessage(msg); //转换为瓦片服务,获取最小最大级别 if (mapServer instanceof TileMapServer) { TileMapServer tileServer = (TileMapServer) mapServer; //瓦片最小级别 minZoom = tileServer.getMinZoom(); //瓦片最大级别 maxZoom = tileServer.getMaxZoom(); //根据级别初始化 initSpinner2(minZoom, maxZoom); } }; };
3
在缓存之前,调用setTilePreFetchListener接口为服务图层设置缓存监听器,在其回调函数中可获取缓存的状态、进度、结果信息。需注意的是这些回调函数都是在子线程中执行的,所以如果需要讲缓存进度信息展示在视图中,需在主线程中处理。
//设置预缓存状态监听类 cacheServerLayer.setTilePreFetchListener(prefetchListener); //瓦片缓存监听器 TilePrefetchListener prefetchListener = new TilePrefetchListener() { public double prefetch(ImageLayerEvent var1) { ImageLayerEventArgs args = var1.getArgs(); //获取预缓存进度 double dPercent = args.getPrefetchPercent(); int dCurTileFetchProgress = (int)(dPercent*100); //设置界面显示瓦片缓存进度值 progressBar.setProgress(dCurTileFetchProgress); Message msg = new Message(); String str = " 更新进度:" + dCurTileFetchProgress +"%"; msg.obj = str; msg.what = 0; mhandler2.sendMessage(msg); return dPercent; } };
4
准备工作完成后,可调用preFetch方法,指定缓存的最小最大级别、地图空间范围开始缓存,返回值为缓存的任务ID。缓存的级别可从第0级到第0级,下载的即为第0级的瓦片。在缓存时,需要确保网络状态良好,避免造成缓存失败的情况。
/** * 预缓存(异步方法) * 参数:预缓存的空间范围,预缓存的最小级别,预缓存的最大级别 */ new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub bFetch = cacheServerLayer.prefetch(rect,minzoom,maxzoom); if (bFetch) { Message m = new Message(); m.what = 1; mhandler2.sendMessage(m); } } }).start();
5
根据缓存监听可判断缓存结果,缓存成功完成后,会在缓存路径中生成缓存文件(如xx.mut文件)。缓存完成后,可调用离线缓存,在未连接网络时同样能够显示地图。
在调用缓存显示地图时,与普通的通过在线请求显示地图方法类似,但需调用setAccessMode方法设置从缓存中读取数据,关键代码如下所示:
mhandler2 = new Handler() { public void handleMessage(Message msg) { super.handleMessage(msg); if (msg.what == 0) { String str = (String) msg.obj; cacheProgress.setText(str); } if (msg.what == 1) { if (msg.arg1 == 0) { cacheProgress.setText("缓存完成"); Toast.makeText(TilePreFetch_Activity.this, "缓存成功。\n缓存路径:" + strCacheDir, Toast.LENGTH_SHORT).show(); //缓存完成之后重置范围 rect = new Rect(); //缓存图层对象 cacheServerLayer = serverLayer1; //缓存完成之后,设置服务图层的数据只从缓存中读取 cacheServerLayer.setAccessMode(MapServerAccessMode.CacheOnly); } if (msg.arg1 == 1) { cacheProgress.setText("缓存失败"); } } }; };